解码分隔符和基于长度的协议
经常需要处理分隔符协议或创建基于它们的协议,例如SMTP、、IMAP、等等。Netty 附带的解码器可以很容易的提取一些序列分隔:
Table 8.5 Decoders for handling delimited and length-based protocols
下图显示了使用”\r\n”分隔符的处理:
- 字节流
- 第一帧
- 第二帧
Figure 8.5 Handling delimited frames
下面展示了如何用 LineBasedFrameDecoder 处理
- 添加一个 LineBasedFrameDecoder 用于提取帧并把数据包转发到下一个管道中的处理程序,在这种情况下就是 FrameHandler
- 添加 FrameHandler 用于接收帧
- 每次调用都需要传递一个单帧的内容
使用 DelimiterBasedFrameDecoder 可以方便处理特定分隔符作为数据结构体的这类情况。如下:
- 传入的数据流是一系列的帧,每个由换行(“\n”)分隔
- 一帧的内容代表一个“命令”:一个名字后跟一些变量参数
清单8.9中显示了的实现的方式。定义以下类:
- 类 Cmd - 存储帧的内容,其中一个 ByteBuf 用于存名字,另外一个存参数
- 类 CmdDecoder - 从重写方法 decode() 中检索一行,并从其内容中构建一个 Cmd 的实例
- 类 CmdHandler - 从 CmdDecoder 接收解码 Cmd 对象和对它的一些处理。
所以关键的解码器是扩展了 LineBasedFrameDecoder
Listing 8.9 Decoder for the command and the handler
- 添加一个 CmdDecoder 到管道;将提取 Cmd 对象和转发到在管道中的下一个处理器
- 添加 CmdHandler 将接收和处理 Cmd 对象
- 命令也是 POJO
- super.decode() 通过结束分隔从 ByteBuf 提取帧
- frame 是空时,则返回 null
- 从帧先于索引以及它之后的片段中实例化一个新的 Cmd 对象
- 处理通过管道的 Cmd 对象
基于长度的协议
基于长度的协议协议在帧头文件里定义了一个帧编码的长度,而不是结束位置用一个特殊的分隔符来标记。表8.6列出了 Netty 提供的两个解码器,用于处理这种类型的协议。
Table 8.6 Decoders for length-based protocols
名称 | 描述 |
---|---|
FixedLengthFrameDecoder | 提取固定长度 |
LengthFieldBasedFrameDecoder | 读取头部长度并提取帧的长度 |
- 字节流 stream
- 4个帧,每个帧8个字节
大部分时候帧的大小被编码在头部,这种情况可以使用LengthFieldBasedFrameDecoder,它会读取头部长度并提取帧的长度。下图显示了它是如何工作的:
- 长度 “0x000C” (12) 被编码在帧的前两个字节
- 后面的12个字节就是内容
- 提取没有头文件的帧内容
Figure 8.7 Message that has frame size encoded in the header
LengthFieldBasedFrameDecoder 提供了几个构造函数覆盖各种各样的头长字段配置情况。清单8.10显示了使用三个参数的构造函数是maxFrameLength,lengthFieldOffset lengthFieldLength。在这
情况下,帧的长度被编码在帧的前8个字节。
Listing 8.10 Decoder for the command and the handler
- 添加一个 LengthFieldBasedFrameDecoder ,用于提取基于帧编码长度8个字节的帧。
- 添加一个 FrameHandler 用来处理每帧